home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pcmagazi / 1988 / 07 / touch.asm next >
Assembly Source File  |  1988-04-11  |  30KB  |  612 lines

  1.                TITLE   TOUCH
  2.                Page    60,132
  3. ;--------------------------------------------------------------------
  4. ;  TOUCH - Set the time/date entry for a file.
  5. ;  PC Magazine - Michael J. Mefford
  6. ;--------------------------------------------------------------------
  7. _TEXT          SEGMENT PUBLIC 'CODE'          ;********************************;
  8.                ASSUME  CS:_TEXT,DS:_TEXT      ;*                              *;
  9.                                               ;*  Requires MASM 2.0 or later  *;
  10.                ORG     80H + 22               ;*     Remember to EXE2BIN      *;
  11. FILE_TIME      DW      ?                      ;*                              *;
  12. FILE_DATE      DW      ?                      ;********************************;
  13. FILE_SIZE_LOW  DW      ?
  14. FILE_SIZE_HIGH DW      ?
  15. FILE_NAME      DB      ?
  16.  
  17.                ORG     100H
  18. START:         JMP     MAIN
  19.  
  20. CR             EQU     13
  21. LF             EQU     10
  22. CTRL_Z         EQU     26
  23. SPACE          EQU     32
  24.  
  25. ;              DATA AREA
  26. ;              ---------
  27.                DB      CR,SPACE,SPACE,SPACE,CR,LF
  28. COPYRIGHT      DB      "TOUCH 1.0 (c) 1988 Ziff Communications Co.",CR,LF
  29. PROGRAMMER     DB      "PC Magazine ",254," Michael J. Mefford",CR,LF,"$"
  30.  
  31. SYNTAX         DB      CR,LF
  32.                DB      CR,LF,"Syntax:  TOUCH filespec [/D date] [/T time]"
  33.                DB      CR,LF,"date = month-day-year"
  34.                DB      CR,LF,"time = hour[:minutes[:seconds]]"
  35.                DB      CR,LF,"Default is system date and time."
  36. CR_LF          DB      CR,LF,"$"
  37.                DB      CTRL_Z
  38.  
  39.  
  40. DATE_FLAG      EQU     1
  41. TIME_FLAG      EQU     2
  42.  
  43. CURRENT_DISK   DB      ?
  44. PATH_END       DW      ?
  45.  
  46. SWITCH_FLAG    DB      0
  47. SWITCH_DATE    DW      0
  48. SWITCH_TIME    DW      0
  49. SYSTEM_DATE    DW      ?
  50. SYSTEM_TIME    DW      ?
  51. TOUCH_DATE     DW      ?
  52. TOUCH_TIME     DW      ?
  53.  
  54. SYNTAX_MSG     DB      "Invalid parameter$"
  55. NOT_FOUND_MSG  DB      "File not found$"
  56.  
  57.  
  58. DELIMITERS     DB      ":-/"
  59.  
  60.  
  61. ;              CODE AREA
  62. ;              ---------
  63.  
  64. ;------------------------------------------------------------------------;
  65. ; First task is to save the current drive and directory defaults.        ;
  66. ; We will be changing the defaults and wish to restore them on exit.     ;
  67. ; The system date and time is retrieved, compressed, and stored to stamp ;
  68. ; the file if no switch request found.  Carriage return linefeed combo   ;
  69. ; sent to display to put air between DOS prompt and TOUCH's messages.    ;
  70. ;------------------------------------------------------------------------;
  71.  
  72. MAIN           PROC    NEAR
  73.  
  74.                CLD                             ;String moves forward.
  75.  
  76.                MOV     AH,9
  77.                MOV     DX,OFFSET COPYRIGHT
  78.                INT     21H
  79.  
  80.                MOV     AH,19H                  ;Get current drive
  81.                INT     21H
  82.                MOV     CURRENT_DISK,AL         ; and save.
  83.                MOV     BYTE PTR CURRENT_DIR,"\"   ;DOS doesn't preface directory
  84.                MOV     SI,OFFSET CURRENT_DIR + 1  ; with slash so we must.
  85.                XOR     DL,DL
  86.                MOV     AH,47H                     ;Get current directory.
  87.                INT     21H
  88.  
  89.                MOV     AH,2AH                  ;Get current date
  90.                INT     21H
  91.                CALL    CONVERT_DATE            ; compress
  92.                MOV     SYSTEM_DATE,DX          ; and store.
  93.                MOV     AH,2CH                  ;Get current time and do same.
  94.                INT     21H
  95.                CALL    CONVERT_TIME
  96.                MOV     SYSTEM_TIME,DX
  97.  
  98.                MOV     DX,OFFSET CR_LF         ;Send carriage return linefeed
  99.                MOV     AH,9                    ; to display just to make our
  100.                INT     21H                     ; output pretty.
  101.  
  102. ;-----------------------------------------------------------------------;
  103. ; Parse the command line for date or time switches.  If found, compress ;
  104. ; decimal number to hex format required by DOS to set date and time.    ;
  105. ;-----------------------------------------------------------------------;
  106.  
  107.                MOV     SI,81H                  ;Point to command line parameter.
  108. FIND_SWITCH:   LODSB                           ;Get a byte.
  109.                CMP     AL,CR                   ;Carriage return marks end.
  110.                JZ      FILESPEC                ;If end, done here.
  111.                CMP     AL,"/"                  ;Is it a switch character?
  112.                JNZ     FIND_SWITCH             ;If no, next byte.
  113.                LODSB                           ;Else, retrieve switch.
  114.                CMP     AL,CR                   ;Did user omit character?
  115.                JZ      FILESPEC                ;If yes, done here.
  116.                AND     AL,5FH                  ;Else, capitalize.
  117.                CMP     AL,"D"                  ;Is it date switch?
  118.                JNZ     CK_TIME                 ;If no, check if time.
  119.                OR      SWITCH_FLAG,DATE_FLAG   ;Else, flag that date included.
  120.                CALL    PARSE_LEADING           ;Parse off leading delimiters.
  121.                CALL    GET_NUMBER              ;Get first number.
  122.                JZ      BAD_PARAMETER           ;Was it a zero or no number?
  123.                MOV     DH,BL                   ;If yes, exit, else store month.
  124.                CALL    GET_NUMBER              ;Get next number.
  125.                JZ      BAD_PARAMETER           ;Was it zero?
  126.                MOV     DL,BL                   ;If yes, exit, else store day.
  127.                CALL    GET_NUMBER              ;Get last number.
  128.                JZ      BAD_PARAMETER           ;Was it zero?
  129.                MOV     CX,BX                   ;If yes, exit, else store year.
  130.                CALL    CONVERT_DATE            ;Convert decimal to compressed
  131.                MOV     SWITCH_DATE,DX          ; hex number and store.
  132.                JMP     SHORT FIND_SWITCH       ;Check for another switch.
  133.  
  134. CK_TIME:       CMP     AL,"T"                  ;Is there a time switch?
  135.                JNZ     FIND_SWITCH             ;If no, check next byte.
  136.                OR      SWITCH_FLAG,TIME_FLAG   ;Else, flag that time included.
  137.                CALL    PARSE_LEADING           ;Handle same as date.
  138.                CALL    GET_NUMBER
  139.                MOV     DH,BL                   ;Store hour in DH.
  140.                CALL    GET_NUMBER
  141.                MOV     DL,BL                   ;Store minutes in DL.
  142.                CALL    GET_NUMBER
  143.                MOV     CX,DX                   ;Store hour and minutes in CX.
  144.                MOV     DH,BL                   ;Store seconds in DH.
  145.                CALL    CONVERT_TIME            ;Convert
  146.                MOV     SWITCH_TIME,DX          ; and store.
  147.  
  148.                JMP     SHORT FIND_SWITCH       ;Check for next switch.
  149.  
  150. ;-----------------------------------------;
  151. ; Lily pad for short jumps to error exit. ;
  152. ;-----------------------------------------;
  153.  
  154. BAD_PARAMETER: JMP     SYNTAX_EXIT             ;Error jumping address.
  155.  
  156. ;------------------------------------------------------------------;
  157. ; Parse drive and/or path delimiters.  Convert filespec to ASCIIZ. ;
  158. ; If drive delimiter found (:), change to requested drive.         ;
  159. ;------------------------------------------------------------------;
  160.  
  161. FILESPEC:      MOV     SI,81H                  ;Point to command line parameter.
  162.                CALL    PARSE_LEADING           ;Parse off leading delimiters.
  163.                PUSH    SI                      ;Save start of filename.
  164.                XOR     BX,BX                   ;Use BX as path specifier flag.
  165. FIND_END:      LODSB                           ;Get a byte.
  166.                CMP     AL,":"                  ;Is it a drive delimiter?
  167.                JNZ     CK_PATH                 ;If no, check if path delimiter.
  168.                MOV     DL,[SI-2]               ;Else, retrieve drive specifier.
  169.                AND     DL,5FH                  ;Capitalize.
  170.                SUB     DL,"A"                  ;Convert to DOS format.
  171.                MOV     AH,0EH                  ;Change drive.
  172.                INT     21H
  173.                MOV     BX,SI                   ;Save as possible filename start.
  174.                JMP     SHORT FIND_END
  175.  
  176. CK_PATH:       CMP     AL,"\"                  ;Is it a path delimiter?
  177.                JNZ     CK_DELIMITER            ;If no, check switch character.
  178.                MOV     BX,SI                   ;Else, save as possible filename.
  179. CK_DELIMITER:  CMP     AL,"/"                  ;Is it a switch delimiter?
  180.                JZ      FOUND_END               ;If yes, end of filespec.
  181.                CMP     AL,SPACE                ;Is it above space character?
  182.                JA      FIND_END                ;If yes, continue until find end.
  183. FOUND_END:     MOV     BYTE PTR [SI-1],0       ;Else, convert to ASCIIZ.
  184.  
  185. ;------------------------------------------------------------------;
  186. ; Save the working default directory so we can restore it on exit. ;
  187. ; If path was found, change to requested directory.                ;
  188. ;------------------------------------------------------------------;
  189.  
  190.                MOV     BYTE PTR WORKING_DIR,"\"   ;DOS doesn't preface directory
  191.                MOV     SI,OFFSET WORKING_DIR + 1  ; with slash so we must.
  192.                XOR     DL,DL
  193.                MOV     AH,47H                  ;Get current directory
  194.                INT     21H                     ; of working drive.
  195.  
  196.                POP     DX                      ;Retrieve filespec start.
  197.                OR      BX,BX                   ;Was there a path specifier?
  198.                JZ      FIND_FILE               ;If no, done here.
  199.                CMP     BYTE PTR [BX-1],":"     ;Was it a drive specifier only?
  200.                JZ      FIND_FILE               ;If yes, done here.
  201.                PUSH    BX                      ;Else, save as filename start.
  202.                CMP     BYTE PTR [BX-2],":"     ;Was it "d:\"?
  203.                JZ      CHANGE_DIR              ;If yes, no adjust.
  204.                CMP     BYTE PTR [BX-2],SPACE   ;Was it plain root "\"?
  205.                JBE     CHANGE_DIR              ;If yes, no adjust.
  206.                DEC     BX                      ;Else point to path delimiter.
  207. CHANGE_DIR:    PUSH    [BX]                    ;Save first byte of filename.
  208.                MOV     BYTE PTR [BX],0         ;Temporary zero so ASCIIZ path.
  209.                MOV     AH,3BH                  ;Change directory.
  210.                INT     21H
  211.                POP     [BX]                    ;Restore first byte of filename.
  212.                POP     DX                      ;Retrieve filename pointer.
  213.  
  214. ;------------------------------------------------------------------------;
  215. ; Ready for business.  Find the file and get a filehandle by opening the ;
  216. ; file for reading.  If no matching filename is found, exit with error   ;
  217. ; message.  If no switch characters were found, then update file with    ;
  218. ; system date and time.  Else, touch with requested value.  If only one  ;
  219. ; switch request was made, don't change the other.  Display results.     ;
  220. ;------------------------------------------------------------------------;
  221.  
  222. FIND_FILE:     MOV     CX,7                    ;Attribute of all files.
  223.                MOV     AH,4EH                  ;Find first matching file.
  224.                INT     21H
  225.                JNC     TOUCH_FILE                ;If found, change date/time.
  226.                MOV     DX,OFFSET NOT_FOUND_MSG   ;Else, display error message
  227.                JMP     SHORT MESSAGE_EXIT        ; and exit.
  228.  
  229. FIND_NEXT:     MOV     AH,4FH                  ;Find next matching file.
  230.                INT     21H
  231.                JC      GOOD_EXIT               ;If failed, we're done.
  232. TOUCH_FILE:    MOV     DX,OFFSET FILE_NAME     ;Else, open file for reading
  233.                MOV     AX,3D00H                ; to get a filehandle.
  234.                INT     21H
  235.                MOV     BX,AX                   ;Filehandle needs to be in BX.
  236.  
  237.                MOV     CX,SYSTEM_TIME          ;Assume request to update
  238.                MOV     DX,SYSTEM_DATE          ; to system date and time.
  239.                MOV     AL,SWITCH_FLAG          ;Retrieve the switch flag.
  240.                CMP     AL,0                    ;Was there a switch?
  241.                JZ      SET_DATE_TIME           ;If no, assumed right.
  242.                MOV     CX,SWITCH_TIME          ;Else, assume it a time request.
  243.                TEST    AL,TIME_FLAG            ;Was there a time switch?
  244.                JNZ     DO_DATE                 ;If yes, assumed right.
  245.                MOV     CX,FILE_TIME            ;Else, use file's time.
  246.  
  247. DO_DATE:       MOV     DX,SWITCH_DATE          ;Assume there was a date request.
  248.                TEST    AL,DATE_FLAG            ;Was there a date switch?
  249.                JNZ     SET_DATE_TIME           ;If yes, assumed right.
  250.                MOV     DX,FILE_DATE            ;Else, use file's date.
  251.  
  252. SET_DATE_TIME: MOV     TOUCH_TIME,CX           ;Save date and time for
  253.                MOV     TOUCH_DATE,DX           ; display purposes.
  254.                MOV     AX,5701H                ;Set file's date and time.
  255.                INT     21H
  256.                JC      SYNTAX_EXIT             ;If failed, exit with message.
  257.  
  258. CLOSE_FILE:    MOV     AH,3EH                  ;Close the file.
  259.                INT     21H
  260.                CALL    DISPLAY_NAME            ;Display complete stats of file.
  261.                JMP     SHORT FIND_NEXT         ;Find next file.
  262.  
  263. ;--------------------------------------------------------------------;
  264. ; Display error message and TOUCH syntax if necessary.  Restore      ;
  265. ; working directory and default drive and directory.  Exit with      ;
  266. ; error code of one if problem; error code of zero if all went well. ;
  267. ;--------------------------------------------------------------------;
  268.  
  269. SYNTAX_EXIT:   MOV     DX,OFFSET SYNTAX_MSG    ;Display "Invalid parameters".
  270. MESSAGE_EXIT:  MOV     AH,9
  271.                INT     21H
  272.                MOV     DX,OFFSET SYNTAX        ;Display TOUCH syntax message.
  273.                MOV     AH,9
  274.                INT     21H
  275.                MOV     AL,1                    ;Exit with error code of 1.
  276.                JMP     SHORT EXIT
  277.  
  278. GOOD_EXIT:     XOR     AL,AL                   ;Exit with error code of 0.
  279. EXIT:          PUSH    AX                      ;Save error code.
  280.                MOV     DX,OFFSET WORKING_DIR   ;Restore working directory.
  281.                MOV     AH,3BH
  282.                INT     21H
  283.                MOV     DL,CURRENT_DISK         ;Restore default drive.
  284.                MOV     AH,0EH
  285.                INT     21H
  286.                MOV     DX,OFFSET CURRENT_DIR   ;Restore default drive directory.
  287.                MOV     AH,3BH
  288.                INT     21H
  289.                POP     AX                      ;Retrieve error code.
  290.                MOV     AH,4CH
  291.                INT     21H                     ;Terminate.
  292.  
  293. MAIN           ENDP
  294.  
  295.                ;***************;
  296.                ;* SUBROUTINES *;
  297.                ;***************;
  298.  
  299. ;---------------------------------------------------;
  300. ; INPUT                                             ;
  301. ;   CX = Year  (1980 - 2099)                        ;
  302. ;   DH = Month (1 - 12)                             ;
  303. ;   DL = Day   (1 - 31)                             ;
  304. ;                                                   ;
  305. ; OUTPUT                                            ;
  306. ;   DX = compressed date in directory entry format. ;
  307. ;                                                   ;
  308. ;        <     DH      > <     DL      >            ;
  309. ;        y y y y y y y m m m m d d d d d            ;
  310. ;                                                   ;
  311. ;              y = year  (0 - 119)                  ;
  312. ;              m = month (1 - 12)                   ;
  313. ;              d = day   (1 - 31)                   ;
  314. ;                                                   ;
  315. ;   BX, CX destroyed.                               ;
  316. ;---------------------------------------------------;
  317.  
  318. CONVERT_DATE   PROC    NEAR
  319.  
  320.                SUB     CX,80                   ;Compress year.
  321.                CMP     CX,1900                 ;Did user abbreviate year?
  322.                JB      SAVE_MONTH              ;If yes, OK.
  323.                SUB     CX,1900                 ;Else, subtract century part.
  324. SAVE_MONTH:    MOV     BL,DH                   ;Store month in BL.
  325.                XOR     BH,BH                   ;Zero in high half.
  326.                SHL     CL,1                    ;Right justify year.
  327.                MOV     DH,CL                   ;Store in DH.
  328.                MOV     CL,5                    ;Shift month left 5 bits.
  329.                SHL     BX,CL
  330.                OR      DX,BX                   ;Add year and month to days.
  331.                RET
  332.  
  333. CONVERT_DATE   ENDP
  334.  
  335. ;---------------------------------------------------;
  336. ; INPUT                                             ;
  337. ;   CH = Hour    (0 - 23)                           ;
  338. ;   CL = Minutes (0 - 59)                           ;
  339. ;   DH = Seconds (0 - 59)                           ;
  340. ;                                                   ;
  341. ; OUTPUT                                            ;
  342. ;   DX = compressed time in directory entry format. ;
  343. ;                                                   ;
  344. ;        <     DH      > <     DL      >            ;
  345. ;        h h h h h m m m m m m x x x x x            ;
  346. ;                                                   ;
  347. ;              h = hour    (0 - 23)                 ;
  348. ;              m = minutes (0 - 59)                 ;
  349. ;              x = two-second increments (0 - 28)   ;
  350. ;                                                   ;
  351. ;   BX, CX destroyed.                               ;
  352. ;---------------------------------------------------;
  353.  
  354. CONVERT_TIME   PROC    NEAR
  355.  
  356.                MOV     BX,CX                   ;Store hour and min. in BX so we   
  357.                MOV     CL,9                    ; can use CL as shift register.
  358.                SHR     DX,CL                   ;Right justify; divide secs by 2.
  359.                MOV     CL,3                    ;Justify left hour.
  360.                SHL     BH,CL
  361.                MOV     DH,BH                   ;Store hour in DH.
  362.                MOV     CL,5
  363.                SHL     BX,CL                   ;Justify minutes.
  364.                OR      DX,BX                   ;Add minutes to hour and seconds.
  365.                RET
  366.  
  367. CONVERT_TIME   ENDP
  368.  
  369. ;----------------------------------------;
  370. ; INPUT                                  ;
  371. ;   DS:SI points to ASCII number string. ;
  372. ;                                        ;
  373. ; OUTPUT                                 ;
  374. ;   BX = hexidecimal number.             ;
  375. ;   DS:SI points to byte after string.   ;
  376. ;   If (ZF) = 1  --  BX =  0             ;
  377. ;   If (ZF) = 0  --  BX <> 0             ;
  378. ;                                        ;
  379. ;   AX, BX, CX, DI destroyed.            ;
  380. ;----------------------------------------;
  381.  
  382. GET_NUMBER     PROC    NEAR
  383.  
  384.                XOR     BX,BX                   ;Start with zero.
  385. PARSE_DELIMIT: LODSB                           ;Get a byte.
  386.                MOV     DI,OFFSET DELIMITERS    ;Is it a delimiter?
  387.                MOV     CX,3
  388.                REPNZ   SCASB
  389.                JZ      PARSE_DELIMIT           ;If yes, get next byte.
  390.  
  391.                MOV     CL,10
  392. NEXT_NUMBER:   XOR     AH,AH                   ;Zero in high half.
  393.                CMP     AL,CR                   ;Is byte a carriage return?
  394.                JZ      NUMBER_END              ;If yes, done.
  395.                CMP     AL,"0"                  ;Is byte a number?
  396.                JB      NUMBER_END
  397.                CMP     AL,"9"
  398.                JA      NUMBER_END              ;If no, done.
  399.                SUB     AL,"0"                  ;Else, convert to hex.
  400.                XCHG    AX,BX                   ;Store in BX.
  401.                MUL     CL                      ;Multiply accumulated by 10.
  402.                ADD     BX,AX                   ;Add new number.
  403.                LODSB                           ;Next byte.
  404.                JMP     SHORT NEXT_NUMBER
  405.  
  406. NUMBER_END:    DEC     SI                      ;Adjust pointer to delimiter.
  407.                OR      BX,BX                   ;Set zero flag if results zero.
  408.                RET
  409.  
  410. GET_NUMBER     ENDP
  411.  
  412. ;--------------------------------------------------------;
  413. ; Parses off leading string delimiters.                  ;
  414. ; If carriage return encountered, jump directly to exit. ;
  415. ;                                                        ;
  416. ; INPUT                                                  ;
  417. ;   DS:SI points to ASCII string.                        ;
  418. ;                                                        ;
  419. ; OUTPUT                                                 ;
  420. ;   DS:SI points to first non-delimiting byte in string. ;
  421. ;                                                        ;
  422. ;   All registers preserved.                             ;
  423. ;--------------------------------------------------------;
  424.  
  425. PARSE_LEADING  PROC    NEAR
  426.  
  427.                LODSB                           ;Get a byte.
  428.                CMP     AL,SPACE                ;Is it a space char or below?
  429.                JA      LEADING_END             ;If no, done here.
  430.                CMP     AL,CR                   ;Is it carriage return?
  431.                JNZ     PARSE_LEADING           ;If no, get next byte.
  432.                JMP     SYNTAX_EXIT             ;Else, immediate error exit.
  433. LEADING_END:   DEC     SI                      ;Adjust pointer to string start.
  434.                RET
  435.  
  436. PARSE_LEADING  ENDP
  437.  
  438. ;------------------------------------------;
  439. ; Stores a filename in DOS DIR format.     ;
  440. ; That is, filename, bytes, date and time. ;
  441. ; Results are printed to display.          ;
  442. ;                                          ;
  443. ; USES                                     ;
  444. ;   FILE_NAME           TOUCH_DATE         ;
  445. ;   FILE_SIZE_LOW       TOUCH_TIME         ;
  446. ;   FILE_SIZE_HIGH      CR_LF              ;
  447. ;                                          ;
  448. ; CALLS                                    ;
  449. ;   STORE_WORD                             ;
  450. ;                                          ;
  451. ; OUTPUT                                   ;
  452. ;   RESULTS = filename DIR style format.   ;
  453. ;                                          ;
  454. ;   AX, BX, CX, DX, SI, DI destroyed.      ;
  455. ;------------------------------------------;
  456.  
  457. DISPLAY_NAME   PROC    NEAR
  458.  
  459.                MOV     SI,OFFSET FILE_NAME     ;Point to filename.
  460.                MOV     DI,OFFSET RESULTS       ;And storage area.
  461.                MOV     AL,SPACE                ;Initiate storage with spaces.
  462.                MOV     CX,40
  463.                REP     STOSB
  464.                MOV     DI,OFFSET RESULTS       ;Point to start of storage again.
  465.                MOV     CX,12                   ;Store 12 bytes of filename.
  466. NEXT_STORE:    LODSB                           ;Get a byte.
  467.                CMP     AL,0                    ;End of filename?
  468.                JZ      END_STORE               ;If yes, finish with blanks.
  469.                CMP     AL,"."                  ;Is it the period?
  470.                JNZ     STORE_BYTE              ;If no, store.
  471.                SUB     CX,3                    ;Else store 3 spaces.
  472.                MOV     AL,SPACE
  473.                REP     STOSB
  474.                ADD     CX,3
  475.                JMP     SHORT NEXT_STORE        ;Get next byte.
  476.  
  477. STORE_BYTE:    STOSB                           ;Store byte.
  478.                LOOP    NEXT_STORE              ;Get next byte.
  479. END_STORE:     MOV     AL,SPACE                ;Pad balance with spaces.
  480.                REP     STOSB
  481.  
  482.                PUSH    DI                      ;Save pointer.
  483.                ADD     DI,8                    ;Move to end of bytes field.
  484.                MOV     DX,FILE_SIZE_LOW        ;Retrieve high and low words
  485.                MOV     AX,FILE_SIZE_HIGH       ; of bytes.
  486.                MOV     BX,10                   ;Convert to decimal.
  487.                STD                             ;Reverse direction.
  488.  
  489. NEXT_SIZE:     MOV     CX,DX                   ;Low word in CX.
  490.                XOR     DX,DX                   ;Zero in high half.
  491.                DIV     BX                      ;Convert to decimal.
  492.                XCHG    AX,CX                   ;Retrieve low word.
  493.                DIV     BX
  494.                XCHG    AX,DX                   ;Retrieve remainder.
  495.                ADD     AL,"0"                  ;Convert to ASCII.
  496.                STOSB                           ;Store it.
  497.                MOV     AX,CX                   ;Are we done?
  498.                OR      CX,DX
  499.                JNZ     NEXT_SIZE               ;If no, divide again.
  500.  
  501.                CLD                             ;Back to forward direction.
  502.                POP     DI                      ;Retrieve pointer.
  503.                ADD     DI,11                   ;Move to date field.
  504. DATE:          MOV     DX,TOUCH_DATE           ;Retrieve date.
  505.                MOV     AX,DX
  506.                MOV     CL,5                    ;Shift to lowest bits.
  507.                SHR     AX,CL
  508.                AND     AX,1111B                ;Mask off all but month.
  509.                MOV     CL,0FFH                 ;Flag as no leading zeros.
  510.                MOV     CH,"-"                  ;Delimiting character.
  511.                CALL    STORE_WORD              ;Store it.
  512.  
  513.                MOV     AX,DX                   ;Retrieve date.
  514.                AND     AX,11111B               ;Mask off all but day.
  515.                XOR     CL,CL                   ;Flag include leading zeros.
  516.                MOV     CH,"-"
  517.                CALL    STORE_WORD              ;Store it.
  518.  
  519.                MOV     AX,DX                   ;Retrieve date for last time.
  520.                MOV     CL,9
  521.                SHR     AX,CL                   ;Mask off all but year.
  522.                ADD     AX,80                   ;Adjust to ASCII.
  523.                CMP     AX,100                  ;Past year 2000?
  524.                JB      DISPLAY_DATE            ;If no, display. Else, adjust for
  525.                SUB     AX,100                  ; next century. (Planning ahead!)
  526. DISPLAY_DATE:  XOR     CL,CL                   ;Display leading zeros.
  527.                MOV     CH,SPACE
  528.                CALL    STORE_WORD              ;Store it.
  529.  
  530. TIME:          INC     DI                      ;Move to time field.
  531.                MOV     DX,TOUCH_TIME           ;Retrieve time.
  532.                MOV     AX,DX
  533.                MOV     CL,11                   ;Shift to hours bits.
  534.                SHR     AX,CL
  535.                PUSH    AX
  536.                CMP     AX,12                   ;Past noon?
  537.                JBE     MERIDIAN
  538.                SUB     AX,12                   ;If yes, adjust.
  539. MERIDIAN:      CMP     AX,0                    ;Midnight?
  540.                JNZ     NOT_MIDNIGHT
  541.                MOV     AX,12                   ;If yes, adjust.
  542. NOT_MIDNIGHT:  MOV     CL,0FFH                 ;Suppress leading zeros.
  543.                MOV     CH,":"
  544.                CALL    STORE_WORD              ;Store it.
  545.  
  546.                MOV     AX,DX                   ;Retrieve time.
  547.                MOV     CL,5                    ;Shift to minutes bits.
  548.                SHR     AX,CL
  549.                AND     AX,111111B              ;Mask off all but minutes.
  550.                XOR     CL,CL
  551.                POP     DX                      ;Retrieve hours.
  552.                MOV     CH,"p"                  ;Assume PM.
  553.                CMP     DX,12                   ;Is it PM?
  554.                JAE     PM
  555.                MOV     CH,"a"                  ;If no, AM.
  556.  
  557. PM:            CALL    STORE_WORD              ;Store it.
  558.                MOV     SI,OFFSET CR_LF         ;Tack on carriage return
  559.                MOVSW                           ; linefeed.
  560.                MOVSB
  561.                MOV     DX,OFFSET RESULTS       ;Display results.
  562.                MOV     AH,9
  563.                INT     21H
  564.                RET                             ;Done here.
  565.  
  566. DISPLAY_NAME   ENDP
  567.  
  568. ;----------------------------------------------;
  569. ; Converts a two byte hex number to decimal    ;
  570. ; and stores the word followed by a delimiter. ;
  571. ;                                              ;
  572. ; INPUT                                        ;
  573. ;   AX = hex number                            ;
  574. ;   BL = 10                                    ;
  575. ;   CH = delimiter character to store.         ;
  576. ;   CL =  0 if zeros are to be stored.         ;
  577. ;   CL = -1 if leading zeros ignored.          ;
  578. ;   ES:DI points to storage.                   ;
  579. ;                                              ;
  580. ; OUTPUT                                       ;
  581. ;   ES:DI points to next storage location.     ;
  582. ;                                              ;
  583. ;   AX destroyed.                              ;
  584. ;----------------------------------------------;
  585.  
  586. STORE_WORD     PROC    NEAR
  587.  
  588.                DIV     BL                      ;Divide by ten.
  589.                ADD     AX,"00"                 ;Convert to ASCII.
  590.                CMP     CL,0                    ;Are we to display leading zero?
  591.                JZ      STORE_IT                ;If yes, store as is.
  592.                CMP     AL,"0"                  ;Is it a leading zero?
  593.                JNZ     STORE_IT                ;If no, store it.
  594.                MOV     AL,SPACE                ;Else, store a space.
  595. STORE_IT:      STOSW
  596.                MOV     AL,CH                   ;Store delimiter character also.
  597.                STOSB
  598.                RET
  599.  
  600. STORE_WORD     ENDP
  601.  
  602. ;--------------------------------------------------------------------------;
  603. ; String storage at end of code to avoid all those zeros in Basic listing. ;
  604. ;--------------------------------------------------------------------------;
  605.  
  606. CURRENT_DIR    LABEL   BYTE
  607. WORKING_DIR    EQU     CURRENT_DIR + 68
  608. RESULTS        EQU     WORKING_DIR + 68
  609.  
  610. _TEXT          ENDS
  611.                END     START
  612.